package modules.cas.singleton2;


import java.lang.reflect.Constructor;

/**
 * 单例模式 - 懒汉式式
 *      存在问题， 单线程没有问题，多线程出现问题
 *      解决：双重检测锁 DCL懒汉式
 *            但是，通过java的反射能破坏
 *
 * @author shengren.yan
 * @create 2021-04-11
 */
public class Singleton4 {

    // 解决： flag 如果定义枚举，可以解决问题
    private static Boolean flag = false;
    // 构造方法私有 ---
    private Singleton4(){
//        // 解决：第一次防御反射破坏
//        synchronized (Singleton4.class){
//            if(null!=singleton){
//                throw new RuntimeException("不要用反射破坏");
//            }
//            System.out.println(Thread.currentThread().getName() + "执行");
//        }

        // 解决：第二次防御反射破坏
        synchronized (Singleton4.class){
            if(flag == false){
                flag= true;
            }else {
                throw new RuntimeException("不要用反射破坏");
            }
            System.out.println(Thread.currentThread().getName() + "执行");
        }

    }

    private volatile static Singleton4 singleton;

    // 如果对象存在就加载，平常不加载
    public static Singleton4 getInstance(){
        // 双重检测锁 DCL懒汉式
        if(null==singleton){
            synchronized (Singleton4.class){
                if(null==singleton){
                    singleton = new Singleton4();
                }
            }
        }
        return singleton;
    }

    // 反射
    public static void main(String[] args) throws Exception {

        // 第一次反射破坏
        Singleton4 instance = Singleton4.getInstance();
        Constructor<Singleton4> declaredConstructor = Singleton4.class.getDeclaredConstructor();
        //关闭权限检测
        declaredConstructor.setAccessible(true);
        Singleton4 instance2 = declaredConstructor.newInstance();
        System.out.println(instance == instance2); //false  //构造方法执行2次，说明new两个对象


        // 第二次反射破坏
//        Constructor<Singleton4> declaredConstructor = Singleton4.class.getDeclaredConstructor();
//        declaredConstructor.setAccessible(true);
//        Singleton4 instance3 = declaredConstructor.newInstance();
//        Singleton4 instance4 = declaredConstructor.newInstance();
//        System.out.println(instance3 == instance4); //false  //通过反射创建2个对象, 构造方法执行2次，说明new两个对象

        // 第三次反射破坏
        // 如果这个变量 flag 被泄露，也容易被反射破坏
        // 解决： flag 使用枚举定义
//        Constructor<Singleton4> declaredConstructor = Singleton4.class.getDeclaredConstructor();
//        declaredConstructor.setAccessible(true);
//        Singleton4 instance3 = declaredConstructor.newInstance();
//        Singleton4 instance4 = declaredConstructor.newInstance();
//        System.out.println(instance3 == instance4); //false  //通过反射创建2个对象, 构造方法执行2次，说明new两个对象


    }

}
